/**
 * VecBall.cpp
 * Coyright (c) 2009 Xiaofeng Gu. All Rights Reserved.
 * Author : Xiaofeng Gu
 *
 * Creation Data : 2009/08/02
 */

#include "stdafx.h"
#include "VecBall.h"
#include "TransNode.h"
#include <math.h>
#include "Global.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CVecBall::CVecBall()
{
}

CVecBall::~CVecBall()
{
}

void CVecBall::Render()
{
	Draw();
}

void CVecBall::Init(CTransNode* pNode)
{
	CBone* pBone = pNode->GetBone();
	CVec dir = (*pBone).Direction();
	Init(CVec((*pBone)[0][0], (*pBone)[0][1], (*pBone)[0][2]), dir);
}

void CVecBall::Init(const CVec& center, const CVec& vec)
{
	m_ballCenter = center;
	m_ballVec = vec;
	m_dBallRadius = m_ballVec.Length();

	CVec temp = m_ballVec;
	temp.Identify();
	if (temp.Equal(0, 0, 1) || temp.Equal(0, 0, -1))
	{
		if (m_ballVec[2] > 0)
		{
			m_dfiAngle = 0;
			m_sitaAngle = SK_PI/2.0;
		}
		else
		{
			m_dfiAngle = 0;
			m_sitaAngle = -SK_PI/2.0;
		}

		m_horizontalVec = CVec(1, 0, 0);
		m_horizontalRadius = 0.0;
	}
	else
	{
		m_horizontalVec = m_ballVec;
		m_horizontalVec.SetZ(0);
		m_horizontalRadius = m_horizontalVec.Length();

		CVec XAixs(1, 0, 0);
		m_dfiAngle = XAixs.CrossAngle(m_horizontalVec);
		if (m_horizontalVec[0] >= 0 && m_horizontalVec[1] >= 0)
		{
			// [0, 90]
		}
		else if (m_horizontalVec[0] < 0 && m_horizontalVec[1] >= 0)
		{
			// (90, 180]
		}
		else if (m_horizontalVec[0] <= 0 && m_horizontalVec[1] < 0)
		{
			// (180, 270]
			ASSERT(m_dfiAngle >= 0 && m_dfiAngle <= SK_PI);
			m_dfiAngle = 2* SK_PI - m_dfiAngle;
		}
		else
		{
			// (270, 360)
			ASSERT(m_dfiAngle >= 0 && m_dfiAngle <= SK_PI);
			m_dfiAngle = 2* SK_PI - m_dfiAngle;
		}

		m_sitaAngle = m_ballVec.CrossAngle(CVec(0, 0, -1));
		m_sitaAngle = m_sitaAngle - SK_PI*0.5;
	}

	m_ballVec.Identify();
	m_horizontalVec.Identify();
	m_lSegmentCount = 30;
}

void CVecBall::ReBuildForFi(double fiValue)
{
	double dDeltaAngle = fiValue - m_dfiAngle;
	m_ballVec.RotateBy(CVec(0, 0, 1), dDeltaAngle);
	m_horizontalVec.RotateBy(CVec(0, 0, 1), dDeltaAngle);
	m_dfiAngle = fiValue;
}

void CVecBall::ReBuildForSita(double sitaValue)
{
	double dDeltaAngle = sitaValue - m_sitaAngle;
	CVec temp = m_ballVec;
	temp.Identify();
	if (temp.Equal(0, 0, 1) || temp.Equal(0, 0, -1))
	{
		CVec Z2 = CVec(0, 0, -1);
		CVec rot = Z2 ^ m_horizontalVec;
		m_ballVec.RotateBy(rot, dDeltaAngle);
	}
	else
	{
		CVec Z2 = CVec(0, 0, -1);
		CVec rot = Z2 ^ m_ballVec;
		m_ballVec.RotateBy(rot, dDeltaAngle);
	}
	m_sitaAngle = sitaValue;

	CVec V = m_ballVec * m_dBallRadius;
	V.SetZ(0);
	m_horizontalRadius = V.Length();
}

void CVecBall::Draw()
{
	CSKGlobal::GetGraphPlotter()->SetColor(255.0f,255.0f,0.0f);
	DrawHCir();
	DrawVCir();
	/*CSKGlobal::GetGraphPlotter()->SetColor(255.0f,0.0f,255.0f);
	DrawHVec();*/
	/*CSKGlobal::GetGraphPlotter()->SetColor(255.0f,0.0f,0.0f);
	DrawHArc();*/
	CSKGlobal::GetGraphPlotter()->SetLineWidth(10.0);
	CSKGlobal::GetGraphPlotter()->SetColor(0.0f,255.0f,0.0f);
	DrawVec();
	CSKGlobal::GetGraphPlotter()->SetLineWidth(1.0);
	/*CSKGlobal::GetGraphPlotter()->SetColor(0.0f,0.0f,255.0f);
	DrawVArc();*/
}

void CVecBall::DrawHCir()
{
	Streams oStreams;
	double dAngleStep = 2 * SK_PI / m_lSegmentCount;
	double dCurAngle = -dAngleStep;
	for (long i = 0; i <= m_lSegmentCount; i ++)
	{
		dCurAngle = dCurAngle + dAngleStep;
		oStreams.push_back(m_ballCenter[0] + m_dBallRadius * cos(dCurAngle));
		oStreams.push_back(m_ballCenter[1] + m_dBallRadius * sin(dCurAngle));
		oStreams.push_back(m_ballCenter[2]);
	}
	CSKGlobal::GetGraphPlotter()->Plot(CGraphPlotter::eLines, oStreams);
}

void CVecBall::DrawVCir()
{
	Streams oStreams;
	double dAngleStep = 2 * SK_PI / m_lSegmentCount;
	double dCurAngle = -dAngleStep;
	for (long i = 0; i <= m_lSegmentCount; i ++)
	{
		dCurAngle = dCurAngle + dAngleStep;
		oStreams.push_back(m_ballCenter[0]);
		oStreams.push_back(m_ballCenter[1] + m_dBallRadius * cos(dCurAngle));
		oStreams.push_back(m_ballCenter[2] + m_dBallRadius * sin(dCurAngle));
	}
	CSKGlobal::GetGraphPlotter()->Plot(CGraphPlotter::eLines, oStreams);
}

void CVecBall::DrawHVec()
{
	Streams oStreams;
	CVec end = m_ballCenter + m_horizontalVec * m_horizontalRadius;
	oStreams.push_back(m_ballCenter[0]);
	oStreams.push_back(m_ballCenter[1]);
	oStreams.push_back(m_ballCenter[2]);
	oStreams.push_back(end[0]);
	oStreams.push_back(end[1]);
	oStreams.push_back(end[2]);
	CSKGlobal::GetGraphPlotter()->Plot(CGraphPlotter::eLines, oStreams);
}

void CVecBall::DrawHArc()
{
	Streams oStreams;
	double dAngleStep = m_dfiAngle / m_lSegmentCount;
	double dCurAngle = -dAngleStep;
	for (long i = 0; i <= m_lSegmentCount; i ++)
	{
		dCurAngle = dCurAngle + dAngleStep;
		oStreams.push_back(m_ballCenter[0] + m_dBallRadius * 0.5 * cos(dCurAngle));
		oStreams.push_back(m_ballCenter[1] + m_dBallRadius * 0.5 * sin(dCurAngle));
		oStreams.push_back(m_ballCenter[2]);
	}
	CSKGlobal::GetGraphPlotter()->Plot(CGraphPlotter::eLines, oStreams);
}

void CVecBall::DrawVec()
{
	Streams oStreams;
	CVec end = m_ballCenter + m_ballVec * m_dBallRadius;
	oStreams.push_back(m_ballCenter[0]);
	oStreams.push_back(m_ballCenter[1]);
	oStreams.push_back(m_ballCenter[2]);
	oStreams.push_back(end[0]);
	oStreams.push_back(end[1]);
	oStreams.push_back(end[2]);
	CSKGlobal::GetGraphPlotter()->Plot(CGraphPlotter::eLines, oStreams);
}

void CVecBall::DrawVArc()
{
	Streams oStreams;
	CVec start = m_ballVec;
	CVec cross = m_ballVec ^ m_horizontalVec;
	if (fabs(cross.Length()) < DELTA) return;
	double dAngle = m_ballVec.CrossAngle(m_horizontalVec);
	double dAngleStep = dAngle / m_lSegmentCount;
	glBegin(GL_LINES);
	for (long i = 0; i <= m_lSegmentCount; i ++)
	{
		start.RotateBy(cross, dAngleStep);
		CVec temp = m_ballCenter + start * m_dBallRadius * 0.5;
		oStreams.push_back(temp[0]);
		oStreams.push_back(temp[1]);
		oStreams.push_back(temp[2]);
	}
	CSKGlobal::GetGraphPlotter()->Plot(CGraphPlotter::eLines, oStreams);
}